package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningRecordFormDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author hrz
 * @since 2025-08-28
 */
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService lessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler DelayTaskHandler;
    private final RabbitMqHelper rabbitMqHelper;
    @Override
    public void submitLearningRecord(LearningRecordFormDTO dto) {
        //1.根据用户id,课表id和小节id更新学习记录
        Long userId = UserContext.getUser();
        Long lessonId = dto.getLessonId();
        Long sectionId = dto.getSectionId();
        //2.根据小节类型判断是视频还是考试
        Integer sectionType = dto.getSectionType();
        boolean finished = Boolean.FALSE; //用来判断这次是不是第一次完成了该小节
        //先去查询旧的学习记录
        LearningRecord byId = queryOldRecord(lessonId,sectionId);
        //判断小节类型
        if(sectionType == 1){
            //3.如果是视频，计算一下学习进度
            Integer duration = dto.getDuration();
            Integer moment = dto.getMoment();
            //3.1计算学习进度 - 向上取整
            int progress = (int) Math.ceil((double) moment / duration * 100);
            if(byId == null){
                //如果是第一次学习,就创建一个新的学习记录
                firstStudy(dto,userId,progress);
            }else{
                if(progress >= 50 && !byId.getFinished()){
                    //3.2如果学习进度大于等于50且是第一次完成，就更新为已完成此小节
                    firstFinished(dto);
                    //把finished设置为true,表示第一次完成了该小节
                    finished = Boolean.TRUE;
                    //第一次完成的话就加10积分,用mq发消息给积分服务
                    rabbitMqHelper.send(
                            MqConstants.Exchange.LEARNING_EXCHANGE,
                            MqConstants.Key.LEARN_SECTION,
                            SignInMessage.of(userId,10)
                    );
                }else if(progress >= 50 && byId.getFinished()){
                    //3.3并不是第一次学完,不过本次也已经学习完毕了,就更新一下学习记录并奖励积分
                    byId.setMoment(moment);
                    byId.setUpdateTime(dto.getCommitTime());
                    DelayTaskHandler.addLearningRecordTask(byId);
                    rabbitMqHelper.send(
                            MqConstants.Exchange.LEARNING_EXCHANGE,
                            MqConstants.Key.LEARN_SECTION,
                            SignInMessage.of(userId,10));
                }else{
                    //3.4未完成,就仅仅更新一下学习记录
                    byId.setMoment(moment);
                    byId.setUpdateTime(dto.getCommitTime());
                    DelayTaskHandler.addLearningRecordTask(byId);
                }
            }
        }else if(sectionType == 2) {
            //4.如果是考试且是第一次完成考试，直接判定为已完成,新增一条记录即可
            examFinished(dto,userId);
            finished = Boolean.TRUE; //如果是已完成,就把finished设置为true
        }
        //去课表中查询课程信息
        updateLesson(dto,finished);
    }


    private void updateLesson(LearningRecordFormDTO dto, boolean finished) {
        LearningLesson ById = lessonService.getById(dto.getLessonId());
        if(ById == null){
            throw new BizIllegalException("课程不存在");
        }
        //判断是否完成了该课程
        if(finished){
            //如果有新的小节完成了,那就查询整个课程信息
            CourseFullInfoDTO Cinfo = courseClient.getCourseInfoById(ById.getCourseId(),
                    false, false);
            //判断已学习完毕的小节数是否等于课程总小节数
            if((ById.getLearnedSections()+1) == Cinfo.getSectionNum()){
                //如果已学习完毕的小节数等于课程总小节数,那就更新课程状态为已学完
                lessonService.lambdaUpdate()
                        .eq(LearningLesson::getId, dto.getLessonId())
                        .set(LearningLesson::getStatus, LessonStatus.FINISHED)
                        .set(LearningLesson::getLatestLearnTime,dto.getCommitTime())
                        .set(LearningLesson::getUpdateTime,dto.getCommitTime())
                        .set(LearningLesson::getLearnedSections, ById.getLearnedSections()+1)
                        .set(LearningLesson::getLatestSectionId,dto.getSectionId())
                        .update();
                return;
            }
        }
        //如果没学习完毕,就只更新一下最后学习的小节数,防止有的状态是刚开始,将状态修改为学习中
        //更新时间和最后学习时间也要修改
        lessonService.lambdaUpdate()
                .eq(LearningLesson::getId, dto.getLessonId())
                .set(LearningLesson::getStatus, LessonStatus.LEARNING)
                .set(LearningLesson::getLatestLearnTime,dto.getCommitTime())
                .set(LearningLesson::getUpdateTime,dto.getCommitTime())
                .set(LearningLesson::getLatestSectionId,dto.getSectionId())
                .update();
    }

    private void examFinished(LearningRecordFormDTO dto, Long userId) {
        LearningRecord record = BeanUtil.copyProperties(dto, LearningRecord.class);
        record.setUserId(userId);
        record.setCreateTime(dto.getCommitTime());
        record.setUpdateTime(dto.getCommitTime());
        record.setFinished(true);
        record.setFinishTime(dto.getCommitTime());
        this.save(record);
    }

    private void firstFinished(LearningRecordFormDTO dto) {
        this.lambdaUpdate()
                .eq(LearningRecord::getLessonId, dto.getLessonId())
                .eq(LearningRecord::getSectionId, dto.getSectionId())
                .set(LearningRecord::getFinished, true)
                .set(LearningRecord::getMoment,dto.getMoment())
                .set(LearningRecord::getUpdateTime,dto.getCommitTime())
                .set(LearningRecord::getFinishTime,dto.getCommitTime())
                .update();
        //再清空该条记录对应的缓存
        DelayTaskHandler.cleanRecordCache(dto.getLessonId(),dto.getSectionId());
    }

    private void firstStudy(LearningRecordFormDTO dto, Long userId, int progress) {
        LearningRecord record = BeanUtil.copyProperties(dto, LearningRecord.class);
        record.setUserId(userId);
        record.setCreateTime(dto.getCommitTime());
        record.setUpdateTime(dto.getCommitTime());
        record.setFinished(false);
        if(progress >= 50){
            record.setFinished(true);
            record.setFinishTime(dto.getCommitTime());
        }
        //最后插入即可
        this.save(record);
    }

    private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
        //1.先查询缓存
        LearningRecord learningRecord =
                DelayTaskHandler.readRecordCache(lessonId, sectionId);
        //2.判断是否为空
        if(learningRecord != null){
            return learningRecord;
        }
        //3.如果缓存为空再去DB查询
        LearningRecord record = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        if(record == null){
            return null;
        }
        //4.如果DB查询到了就放入缓存
        DelayTaskHandler.writeRecordCache(record);
        return record;
    }
}